package com.event.management.backend.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import com.event.management.backend.dto.LoginParam;
import com.event.management.backend.dto.LoginResponseDTO;
import com.event.management.backend.dto.UserInfoDTO;
import com.event.management.backend.service.LoginLogsService;
import com.event.management.backend.service.UsersService;
import com.event.management.backend.util.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 认证控制器
 */
@Api(tags = "用户认证接口")
@RestController
@RequestMapping("/api/auth")
@Slf4j
public class AuthController {

    @Autowired
    private UsersService usersService;
    
    @Autowired
    private LoginLogsService loginLogsService;

    /**
     * 用户登录
     * @param loginParam 登录参数
     * @return 登录结果
     */
    @ApiOperation(value = "用户登录", notes = "用户登录，颁发Token")
    @PostMapping("/login")
    public Result<LoginResponseDTO> login(@RequestBody @Validated LoginParam loginParam) {
        log.info("用户登录请求: {}", loginParam.getUsername());
        
        try {
            // 执行登录操作前，先检查用户角色
            String role = usersService.getUserRoleByUsername(loginParam.getUsername());
            
            // 用户不存在的情况会在login方法中处理
            if (role != null && "user".equals(role)) {
                log.warn("普通用户尝试登录系统: {}", loginParam.getUsername());
                return Result.error("普通用户不允许登录系统，请联系管理员");
            }
            
            // 执行登录操作
            LoginResponseDTO loginResponse = usersService.login(loginParam);
            
            // 记录登录成功日志
            String ipAddress = getRemoteIp();
            loginLogsService.addLoginLog(loginResponse.getUserInfo().getId(), ipAddress, "success");
            
            // 在响应中设置明确的token字段到响应头，便于前端处理
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                // 获取响应对象并设置token到响应头
                attributes.getResponse().setHeader("Authorization", loginResponse.getToken());
                attributes.getResponse().setHeader("Access-Control-Expose-Headers", "Authorization");
            }
            
            log.info("用户登录成功: {}, token: {}", loginParam.getUsername(), loginResponse.getToken());
            return Result.success(loginResponse);
        } catch (Exception e) {
            // 记录登录失败日志
            // 查询用户ID（如果用户存在）
            Integer userId = usersService.getUserIdByUsername(loginParam.getUsername());
            if (userId != null) {
                String ipAddress = getRemoteIp();
                loginLogsService.addLoginLog(userId, ipAddress, "fail");
            }
            
            // 返回明确的错误信息
            log.error("用户登录失败: {}", e.getMessage());
            return Result.error("登录失败：" + e.getMessage());
        }
    }

    /**
     * 用户登出
     * @return 登出结果
     */
    @ApiOperation(value = "用户登出", notes = "清除当前Token并登出")
    @PostMapping("/logout")
    @SaCheckLogin
    public Result<String> logout() {
        String userId = StpUtil.getLoginIdAsString();
        log.info("用户登出: {}", userId);
        StpUtil.logout();
        return Result.success("登出成功");
    }

    /**
     * 获取当前登录用户信息
     * @return 用户信息
     */
    @ApiOperation(value = "获取当前用户信息", 
            notes = "获取当前登录用户的详细信息，包括基本资料(ID、用户名、角色)、" +
                    "个人信息(真实姓名、性别、邮箱、手机号、兴趣爱好、生日、个人简介、头像、地址、职业)、" +
                    "账户信息(创建时间、更新时间)和登录统计(最后登录IP、最后登录时间)")
    @GetMapping("/me")
    @SaCheckLogin
    public Result<UserInfoDTO> getCurrentUser() {
        UserInfoDTO userInfo = usersService.getCurrentUserInfo();
        return Result.success(userInfo);
    }
    
    /**
     * 检查用户角色和权限状态
     * @return 角色和权限信息
     */
    @ApiOperation(value = "检查角色状态", notes = "用于调试用户角色和权限")
    @GetMapping("/check-role")
    @SaCheckLogin
    public Result<Map<String, Object>> checkRoleStatus() {
        Map<String, Object> result = new HashMap<>();
        
        // 获取当前用户ID
        String loginId = StpUtil.getLoginIdAsString();
        result.put("userId", loginId);
        
        // 获取当前用户角色列表
        result.put("roleList", StpUtil.getRoleList());
        
        // 检查是否有admin角色
        boolean isAdmin = StpUtil.hasRole("admin");
        result.put("isAdmin", isAdmin);
        
        // 尝试强制设置admin角色（仅用于调试）
        if (!isAdmin && "1".equals(loginId)) {
            log.info("为用户ID=1设置admin角色");
            StpUtil.getRoleList().add("admin");
            result.put("adminRoleSet", true);
            result.put("newRoleList", StpUtil.getRoleList());
        }
        
        return Result.success(result);
    }
    
    /**
     * 管理员专用测试接口
     * @return 测试结果
     */
    @ApiOperation(value = "管理员测试接口", notes = "测试@SaCheckRole注解")
    @GetMapping("/admin-only")
    @SaCheckRole("admin")
    public Result<String> adminOnly() {
        return Result.success("您是管理员，可以访问此接口");
    }
    
    /**
     * 获取远程IP地址
     * @return IP地址
     */
    private String getRemoteIp() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            String ip = request.getHeader("X-Forwarded-For");
            if (ip != null && !"unknown".equalsIgnoreCase(ip)) {
                // 多次反向代理后会有多个IP值，第一个IP才是真实IP
                int index = ip.indexOf(",");
                if (index != -1) {
                    return ip.substring(0, index);
                } else {
                    return ip;
                }
            }
            ip = request.getHeader("X-Real-IP");
            if (ip != null && !"unknown".equalsIgnoreCase(ip)) {
                return ip;
            }
            return request.getRemoteAddr();
        }
        return "unknown";
    }
} 